package me.yushuai.wukong.base.service.impl;

import me.yushuai.wukong.base.api.dto.CartonDTO;
import me.yushuai.wukong.base.api.dto.CreateCartonDTO;
import me.yushuai.wukong.base.api.dto.PagingSearchCarton;
import me.yushuai.wukong.base.api.dto.UpdateCartonDTO;
import me.yushuai.wukong.base.convertor.CartonConvertor;
import me.yushuai.wukong.base.entity.Carton;
import me.yushuai.wukong.base.repository.CartonRepository;
import me.yushuai.wukong.base.service.CartonService;
import me.yushuai.wukong.common.dto.PageDTO;
import me.yushuai.wukong.common.error.WuKongException;
import me.yushuai.wukong.common.exceptin.DuplicateBizIdException;
import me.yushuai.wukong.common.exceptin.NotExistException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 装箱关联
 *
 * @author zhoushuai@189.cn
 * @since 2022-09-09
 */
@Service
public class CartonServiceImpl implements CartonService {

    private final CartonRepository cartonRepository;

    private final CartonConvertor cartonConvertor;

    @Autowired
    public CartonServiceImpl(CartonRepository cartonRepository, CartonConvertor cartonConvertor) {
        this.cartonRepository = cartonRepository;
        this.cartonConvertor = cartonConvertor;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = WuKongException.class)
    public Long createCarton(CreateCartonDTO createCartonDTO) throws DuplicateBizIdException {
        //1. 检查仓库编码是否合法

        //2. 检查装箱编码是否可用
        final String bizId = createCartonDTO.getBizId();
        if (this.cartonRepository.existsByBizId(bizId)) {
            throw new DuplicateBizIdException(bizId, Carton.class);
        }

        //3. 新增装箱信心
        final Carton carton = this.cartonConvertor.mapToCarton(createCartonDTO);
        this.cartonRepository.save(carton);
        //4. 返回新建成功的装箱编号
        return carton.getId();
    }

    @Override
    public Long updateCarton(UpdateCartonDTO updateCartonDTO) throws NotExistException {
        //1. 检查仓库编码是否合法
        final Long cartonId = updateCartonDTO.getCartonId();
        final Carton carton = this.cartonRepository.findById(cartonId)
                .orElseThrow(() -> new NotExistException(cartonId, Carton.class));

        //2. DTO转换为DO并更新数据
        this.cartonConvertor.mapToCarton(updateCartonDTO, carton);
        this.cartonRepository.save(carton);

        //3. 返回被修改的装箱编码
        return cartonId;
    }

    @Override
    public void deleteCarton(Long cartonId) throws NotExistException {

        //1. 检查cartonId是否存在
        if (!this.cartonRepository.existsById(cartonId)) {
            throw new NotExistException(cartonId, Carton.class);
        }

        //2. 执行删除操作
        this.cartonRepository.deleteById(cartonId);

    }

    @Override
    public CartonDTO findById(Long cartonId) throws NotExistException {

        //1. 执行查询操作
        final Optional<Carton> cartonOptional = this.cartonRepository.findById(cartonId);

        final Carton carton = cartonOptional
                .orElseThrow(() -> new NotExistException(cartonId, Carton.class));

        //3. 转换并返回对象
        return this.cartonConvertor.mapToDto(carton);
    }

    @Override
    public PageDTO<CartonDTO> pagingSearchCarton(PagingSearchCarton pagingSearch) {
        //1. 分页条件查询
        final PageRequest pageRequest = PageRequest.of(pagingSearch.getCurrent(), pagingSearch.getSize());
        final Specification<Carton> spec = (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if (StringUtils.hasText(pagingSearch.getCartonCode())) {
                list.add(criteriaBuilder.equal(root.get("cartonCode").as(String.class), pagingSearch.getCartonCode()));
            }
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        //2. 执行查询操作
        Page<Carton> cartonPage = this.cartonRepository.findAll(spec, pageRequest);


        //3. 对象转换并返回并返回
        pagingSearch.setTotal(cartonPage.getTotalElements());
        final List<CartonDTO> list = this.cartonConvertor.mapToDtoList(cartonPage.getContent());
        return PageDTO.of(pagingSearch, list);
    }

    @Override
    public void assertCartonIdHasExist(Long cartonId) throws NotExistException {
        if (!this.checkCartonIdExist(cartonId)) {
            throw new NotExistException(cartonId, "carton.cartonId.NotFound");
        }
    }

    @Override
    public void assertCartonIdAndCartonCodeMatch(Long cartonId, String cartonCode) throws NotExistException {
        Specification<Carton> spec = (root, query, criteriaBuilder) -> criteriaBuilder.and(
                criteriaBuilder.equal(root.get("cartonId").as(String.class), cartonId),
                criteriaBuilder.equal(root.get("cartonCode").as(String.class), cartonCode)
        );

        if (this.cartonRepository.count(spec) == 0) {
            final Object[] params = new Object[]{cartonId, cartonCode};
            throw new NotExistException(params, "carton.cartonIdAndCartonCode.NotMatch");
        }
    }

    @Override
    public void assertCartonCodeNotExist(String cartonCode) throws WuKongException {
        if (this.existByBizId(cartonCode)) {
            throw new WuKongException("carton.cartonCode.HasExist");
        }
    }

    @Override
    public boolean checkCartonIdExist(Long cartonId) {
        return this.cartonRepository.existsById(cartonId);
    }


    @Override
    public boolean existByBizId(String cartonCode) {
        return this.cartonRepository.existsByBizId(cartonCode);
    }
}




